package controllers;

import com.google.gson.Gson;
import jobs.CrawlerJob;
import models.crawlers.Slami;
import models.crawlers.common.SessionParams;
import models.crawlers.common.ShopCrawler;
import models.crawlers.common.SitePathInfo;
import models.crawlers.common.WebSiteInfo;
import models.entities.CrawlerEntity;
import models.exceptions.GetEntityException;
import models.helpers.ImageHelper;
import models.helpers.StringHelper;
import models.repository.CrawlerRepositorySQL;
import models.repository.common.CrawlerRepository;
import play.Play;
import play.cache.Cache;
import play.mvc.Controller;
import play.mvc.With;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@With(Secure.class)
public class Crawler extends Controller {
    private static CrawlerRepository crawlerRepository = new CrawlerRepositorySQL();


    @Check("admin")
    public static void startNewScan(String crawlerName) throws Exception {
        crawlerName = (crawlerName == null || crawlerName.equals("")) ? Slami.class.getSimpleName() : crawlerName;
        stopCrawler();
        startCrawler(crawlerName);
        getStatus(crawlerName);
    }
    
    @Check("admin")
    public static void refresh(String crawlerName){
        
    }

    @Check("admin")
    public static void stopCrawler(String crawlerName) throws IOException, GetEntityException {
        stopCrawler();
        getStatus(crawlerName);
    }

    private static void stopCrawler() {
        Object crawlerThread = Cache.get("crawlerthread");
        if (crawlerThread != null) {
            CrawlerJob crawlerJob = (CrawlerJob) crawlerThread;
            crawlerJob.stopCrawler();
            Cache.delete("crawlerthread");
        }
    }

    @Check("admin")
    private static void startCrawler(String crawlerName) throws Exception {
        ShopCrawler crawler = getCrawler(crawlerName);
        String dataPath = Play.getFile("data").toString();
        CrawlerEntity crawlerInfo = crawlerRepository.getCrawlerInfo(crawlerName);
        CrawlerJob crawlerJob = new CrawlerJob(dataPath, crawler, crawlerInfo);
        crawlerJob.now();
        Cache.set("crawlerthread", crawlerJob);
    }

    @Check("admin")
    public static void getStatus(String crawlerName) throws IOException, GetEntityException {
        CrawlerEntity crawlerInfo = crawlerRepository.getCrawlerInfo(crawlerName);
        WebSiteInfo webSiteInfo = getWebSiteInfo(crawlerInfo);
        if (request.isAjax()) {
            renderJSON(webSiteInfo);
        } else {
            if (webSiteInfo == null) {
                webSiteInfo = new WebSiteInfo(new SitePathInfo(), 0, 0);
            }
            SitePathInfo productsCategory = getProductsCategory(webSiteInfo.currentSitePath);
            String categoryPercent = getCategoryPercent(webSiteInfo);
            String productsPercent = getProductsPercent(productsCategory);
            render("Crawler/crawlerStatus.html",
                    crawlerName,
                    webSiteInfo,
                    productsCategory,
                    categoryPercent,
                    productsPercent);
        }
    }

    private static String getProductsPercent(SitePathInfo productsCategory) {
        return StringHelper.getPercentString(productsCategory.childIndex, productsCategory.itemsCount);
    }

    private static String getCategoryPercent(WebSiteInfo webSiteInfo) {
        return StringHelper.getPercentString(webSiteInfo.categoryIndex, webSiteInfo.categoriesCount);
    }



    private static SitePathInfo getProductsCategory(SitePathInfo currentSitePath) {
        if (currentSitePath.containsProducts)
            return currentSitePath;
        if (currentSitePath.childPathElement != null)
            return getProductsCategory(currentSitePath.childPathElement);
        else {
            currentSitePath.childPathElement = new SitePathInfo();
            currentSitePath.childPathElement.title = "";
            currentSitePath.childPathElement.url = "#";
            return currentSitePath;
        }
    }

    private static WebSiteInfo getWebSiteInfo(CrawlerEntity crawlerInfo) {
        Gson gson = new Gson();
        WebSiteInfo webSiteInfo = gson.fromJson(crawlerInfo.webSiteInfo, WebSiteInfo.class);
        return webSiteInfo;
    }

    @Check("admin")
    public static void resumeSession(String crawlerName) throws Exception {
        startCrawler(crawlerName);
        getStatus(crawlerName);
    }

    @Check("admin")
    private static ShopCrawler getCrawler(String crawlerName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        ShopCrawler crawler;
        crawler = (ShopCrawler) Class.forName(String.format("models.crawlers.%1$s", crawlerName)).newInstance();
        return crawler;
    }

    public static void list() throws GetEntityException, IOException {
        CrawlerRepository crawlerRepository = new CrawlerRepositorySQL();
        List<CrawlerEntity> crawlers = crawlerRepository.getAllCrawlers();
        render(crawlers);
    }

    public static void getImage(String imageName) throws IOException {
        InputStream image = ImageHelper.getCrawlerImage(Play.getFile("data").toString(), imageName);
        renderBinary(image, imageName, "image/png", true);
    }
    
    @Check("admin")
    public static void showSessions(String crawlerTitle) throws IOException {
        CrawlerRepository repository = new CrawlerRepositorySQL();
        List<SessionParams> sessions = repository.getSessions(crawlerTitle);
        render(sessions, crawlerTitle);
    }




}
